package com.badlogic.agdwikisamples;

import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;

import com.badlogic.agdwikisamples.utils.BenchmarkActivity;

public class BulkPutBenchmark extends BenchmarkActivity
{
	static
	{
		System.loadLibrary( "agd-wiki-samples" );
	}
	
	static final int REPEATS = 1;

	@Override
	public void benchmark() {
		ByteBuffer buffer = ByteBuffer.allocateDirect( 1024*1024 * Float.SIZE / 8 );
		buffer.order(ByteOrder.nativeOrder());			
		FloatBuffer floatBuffer = buffer.asFloatBuffer();
		IntBuffer intBuffer = buffer.asIntBuffer();
		
		float[] floatArray = new float[1024*1024];
		int[] intArray = new int[1024*1024];
		int len = floatArray.length;
		
		// single put
		tic();
		for( int j = 0; j < REPEATS; j++ )
		{
			for( int i = 0; i < len; i++ )
				floatBuffer.put( floatArray[i] );
			floatBuffer.clear();
		}
		toc( "buffer.put(float)" );

		// single indexed put
		tic();
		for( int j = 0; j < REPEATS; j++ )
		{
			for( int i = 0; i < len; i++ )
				floatBuffer.put( i, floatArray[i] );
			floatBuffer.clear();
		}
		toc( "buffer.put(i,float)" );
		
		// bulk put
		tic();
		for( int j = 0; j < REPEATS; j++ )
		{
			floatBuffer.put( floatArray );
			floatBuffer.clear();
		}
		toc( "buffer.put(float[])" );
		
		// convert bulk put
		tic();
		for( int j = 0; j < REPEATS; j++ )
		{
			for( int i = 0; i < len; i++ )
				intArray[i] = Float.floatToIntBits(floatArray[i]);
			intBuffer.put(intArray);
			intBuffer.clear();
		}
		toc( "buffer.put(int[])" );
		
		// jni bulk put
		tic();
		for( int j = 0; j < REPEATS; j++ )
		{
			copy( floatArray, floatBuffer, floatArray.length, 0 );
			floatBuffer.clear();
		}
		toc( "jniCopy(float[],buffer)" );		
		info( "done" );
	}

	/**
	 * Copies numFloats floats from src starting at offset to dst. Dst is 
	 * assumed to be a direct {@link Buffer}. The method will crash if that
	 * is not the case. The position and limit of the buffer are ignored, the copy
	 * is placed at position 0 in the buffer. After the copying process the position
	 * of the buffer is set to 0 and its limit is set to numFloats * 4 if it is a
	 * ByteBuffer and numFloats if it is a FloatBuffer. In case the Buffer is neither 
	 * a ByteBuffer nor a FloatBuffer the limit is not set. This is an expert method,
	 * use at your own risk.  
	 * 
	 * @param src the source array
	 * @param dst the destination buffer, has to be a direct Buffer
	 * @param numFloats the number of floats to copy
	 * @param offset the offset in src to start copying from
	 */
	public static void copy( float[] src, Buffer dst, int numFloats, int offset )
	{		
		copyJni( src, dst, numFloats, offset );
		dst.position(0);  
	
		if( dst instanceof ByteBuffer )  
			dst.limit(numFloats << 2);
		else
		if( dst instanceof FloatBuffer ) 
			dst.limit(numFloats);
	}
	
	private native static void copyJni( float[] src, Buffer dst, int numFloats, int offset );
}
